#include "label_list_widget.h"

HTMLDelegate::HTMLDelegate(QObject* parent)
	: QStyledItemDelegate(parent)
{
}

void HTMLDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	painter->save();

	QStyleOptionViewItem options(option);
	initStyleOption(&options, index);

	QTextDocument doc;
	doc.setHtml(options.text);
	options.text = QString();

	const QWidget* widget = options.widget;
	QStyle* style = widget ? widget->style() : QApplication::style();
	style->drawControl(QStyle::CE_ItemViewItem, &options, painter, widget);

	QAbstractTextDocumentLayout::PaintContext ctx;

	if (option.state & QStyle::State_Selected)
	{
		ctx.palette.setColor(
			QPalette::Text,
			option.palette.color(QPalette::Active, QPalette::HighlightedText));
	}
	else
	{
		ctx.palette.setColor(QPalette::Text,
		                     option.palette.color(QPalette::Active, QPalette::Text));
	}

	QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &options, widget);

	if (index.column() != 0)
	{
		textRect.adjust(5, 0, 0, 0);
	}

	const int thefuckyourshitup_constant = 4;
	int margin = (option.rect.height() - options.fontMetrics.height()) / 2;
	margin = margin - thefuckyourshitup_constant;
	textRect.setTop(textRect.top() + margin);

	painter->translate(textRect.topLeft());
	painter->setClipRect(textRect.translated(-textRect.topLeft()));
	doc.documentLayout()->draw(painter, ctx);

	painter->restore();
}

QSize HTMLDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	QTextDocument doc;
	doc.setHtml(index.data().toString());
	const int thefuckyourshitup_constant = 4;
	return QSize(static_cast<int>(doc.idealWidth()),
	             static_cast<int>(doc.size().height() - thefuckyourshitup_constant));
}

LabelListWidgetItem::LabelListWidgetItem(const QString& text, Shape* shape)
	: QStandardItem()
{
	setText(text);
	setShape(shape);

	setCheckable(true);
	setCheckState(Qt::Checked);
	setEditable(false);
	setTextAlignment(Qt::AlignBottom);
}

QStandardItem* LabelListWidgetItem::clone() const
{
	return new LabelListWidgetItem(text(), shape());
}

void LabelListWidgetItem::setShape(::Shape* shape)
{
	QVariant var = QVariant::fromValue(shape);
	setData(var, Qt::UserRole);
}

::Shape* LabelListWidgetItem::shape() const
{
	return data(Qt::UserRole).value<::Shape*>();
}

bool StandardItemModel::removeRows(int row, int count, const QModelIndex& parent)
{
	bool ret = QStandardItemModel::removeRows(row, count, parent);
	emit itemDropped();
	return ret;
}

LabelListWidget::LabelListWidget(QWidget* parent)
	: QListView(parent)
{
	setWindowFlags(Qt::Window);
	auto* model = new StandardItemModel(this);
	model->setItemPrototype(new LabelListWidgetItem());
	setModel(model);
	setItemDelegate(new HTMLDelegate(this));
	setSelectionMode(QAbstractItemView::ExtendedSelection);
	setDragDropMode(QAbstractItemView::InternalMove);
	setDefaultDropAction(Qt::MoveAction);

	connect(this, &QListView::doubleClicked, this, &LabelListWidget::itemDoubleClickedEvent);
	connect(selectionModel(), &QItemSelectionModel::selectionChanged, this,
	        &LabelListWidget::itemSelectionChangedEvent);
}

int LabelListWidget::size() const
{
	return model()->rowCount();
}

LabelListWidgetItem* LabelListWidget::at(int i) const
{
	return static_cast<LabelListWidgetItem*>(
		static_cast<QStandardItemModel*>(model())->item(i));
}

QList<LabelListWidgetItem*> LabelListWidget::items() const
{
	QList<LabelListWidgetItem*> itemList;
	for (int i = 0; i < size(); ++i)
	{
		itemList.append(at(i));
	}
	return itemList;
}

void LabelListWidget::itemDoubleClickedEvent(const QModelIndex& index)
{
	auto* item = static_cast<LabelListWidgetItem*>(static_cast<QStandardItemModel*>(model())->itemFromIndex(index));
	emit itemDoubleClicked(item);
}

void LabelListWidget::itemSelectionChangedEvent(const QItemSelection& selected, const QItemSelection& deselected)
{
	QList<LabelListWidgetItem*> selectedItems;
	for (const auto& index : selected.indexes())
	{
		selectedItems.append(
			static_cast<LabelListWidgetItem*>(static_cast<QStandardItemModel*>(model())->itemFromIndex(index)));
	}

	QList<LabelListWidgetItem*> deselectedItems;
	for (const auto& index : deselected.indexes())
	{
		deselectedItems.append(
			static_cast<LabelListWidgetItem*>(static_cast<QStandardItemModel*>(model())->itemFromIndex(index)));
	}

	emit itemSelectionChanged(selectedItems, deselectedItems);
}

QList<LabelListWidgetItem*> LabelListWidget::selectedItems() const
{
	QList<LabelListWidgetItem*> selectedItems;
	for (const auto& index : selectedIndexes())
	{
		selectedItems.append(
			static_cast<LabelListWidgetItem*>(static_cast<QStandardItemModel*>(model())->itemFromIndex(index)));
	}
	return selectedItems;
}

void LabelListWidget::scrollToItem(LabelListWidgetItem* item)
{
	QModelIndex index = static_cast<QStandardItemModel*>(model())->indexFromItem(item);
	scrollTo(index);
}

void LabelListWidget::addItem(LabelListWidgetItem* item)
{
	if (!item)
	{
		qWarning("Item must be a LabelListWidgetItem");
		return;
	}
	static_cast<QStandardItemModel*>(model())->setItem(model()->rowCount(), 0, item);
	item->setSizeHint(itemDelegate()->sizeHint(QStyleOptionViewItem(), QModelIndex()));
}

void LabelListWidget::removeItem(LabelListWidgetItem* item)
{
	QModelIndex index = static_cast<QStandardItemModel*>(model())->indexFromItem(item);
	model()->removeRows(index.row(), 1);
}

void LabelListWidget::selectItem(LabelListWidgetItem* item)
{
	QModelIndex index = static_cast<QStandardItemModel*>(model())->indexFromItem(item);
	selectionModel()->select(index, QItemSelectionModel::Select);
}

LabelListWidgetItem* LabelListWidget::findItemByShape(::Shape* shape)
{
	for (int row = 0; row < model()->rowCount(); ++row)
	{
		auto* item = static_cast<LabelListWidgetItem*>(static_cast<QStandardItemModel*>(model())->item(row, 0));
		if (item->shape() == shape)
		{
			return item;
		}
	}
	qWarning() << "Cannot find shape:" << shape;
	return nullptr;
}

void LabelListWidget::clear()
{
	static_cast<QStandardItemModel*>(model())->clear();
}
